using System;
using System.Buffers;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using UMC.Bridge;
using UMC.Data;
using UMC.ITME.Entities;
using UMC.Net;
using UMC.SshNet.Abstractions;

namespace UMC.ITME
{
    class HttpBridgeProxy : NetBridgeReader, INetBridgePrepare
    {

        bool _IsOver;
        public override bool IsOver => _IsOver;
        RelayAsyncArgs.Relay targetStream;
        DataWriter dataWriter;
        int _sendQty, _receiveQty;
        public HttpBridgeProxy(DataWriter writer, StringValue value)
        {
            this.dataWriter = writer;
            Init(value);
        }
        public int ConfigKey
        {
            get; set;
        }
        int _size = 0;
        long _sharePosition = -1;
        public HttpBridgeProxy(Socket socket)
        {
            targetStream = new RelayAsyncArgs.Relay(socket);
        }

        public async Task Init(IPAddress bridgeIP, int bridgePort, StringValue domain, ushort remotePort, long sharePosition, int count)
        {

            receiveData = System.Buffers.ArrayPool<byte>.Shared.Rent(512);

            receiveData[0] = 0x03;
            domain.Span.CopyTo(receiveData.AsSpan(1));//.Span)
            int size = domain.Length + 1;
            BitConverter.TryWriteBytes(receiveData.AsSpan(size), remotePort);
            size += 2;
            bool isProxy = false;
            this._sharePosition = sharePosition;
            this._size = count;
            try
            {

                this.dataWriter = await HttpBridgeServier.BridgeStart(bridgeIP, bridgePort, receiveData.AsMemory(0, size), this);
                if (this.dataWriter == null)
                {
                    return;
                }
                isProxy = true;
            }
            finally
            {
                if (isProxy == false)
                {
                    System.Buffers.ArrayPool<byte>.Shared.Return(receiveData);
                    receiveData = Array.Empty<byte>();
                    this.targetStream.IsConnect = false;
                    this.targetStream.Socket.Close();
                    this.targetStream.Socket.Dispose();
                }
            }
        }
        byte[] receiveData = Array.Empty<byte>();

        async void Init(StringValue domain)
        {
            Socket socket = null;
            var timeOut = new CancellationTokenSource(60000);
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                var ipAddresses = await NetProxy.DNSToIPAsync(domain.Slice(0, domain.Length - 2).UTF8(), timeOut.Token);
                if (ipAddresses.Length > 0)
                {
                    if (UMC.ITME.Utility.IsInternalIP(ipAddresses[0]) == false)
                    {
                        await socket.ConnectAsync(ipAddresses[0], BitConverter.ToUInt16(domain.Slice(domain.Length - 2).Span), timeOut.Token);
                        this.targetStream = new RelayAsyncArgs.Relay(socket);
                        SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                        receiveData = System.Buffers.ArrayPool<byte>.Shared.Rent(512);
                        eventArgs.SetBuffer(receiveData);
                        eventArgs.Completed += Http;
                        dataWriter.Prepare(new byte[1] { 0x00 });
                        if (!socket.ReceiveAsync(eventArgs))
                        {
                            ProcessReceive(eventArgs);
                        }
                        return;
                    }
                }
            }
            catch
            {
                GC.Collect();
                // GC.WaitForPendingFinalizers();
            }
            socket?.Close();
            socket?.Dispose();
            this.dataWriter.Prepare(new byte[1] { 0x01 });
            this.dataWriter.Write(Array.Empty<byte>());
            this.dataWriter.Flush();
            this.dataWriter.Dispose();
            this._IsOver = true;
            if (receiveData.Length > 0)
            {
                System.Buffers.ArrayPool<byte>.Shared.Return(receiveData);
                receiveData = Array.Empty<byte>();
            }
        }
        private void Http(object sender, SocketAsyncEventArgs e)
        {
            if (e.LastOperation == SocketAsyncOperation.Receive)
            {
                ProcessReceive(e);
            }
            else
            {

                e.Dispose();
                Close();
            }
        }
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                targetStream.ActiveTime = Utility.TimeSpan();
                _sendQty += e.BytesTransferred;
                dataWriter.Write(receiveData.AsSpan(0, e.BytesTransferred));
                dataWriter.Flush();
                while (this.targetStream.IsConnect && !this.targetStream.Socket.ReceiveAsync(e))
                {
                    if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                    {
                        targetStream.ActiveTime = Utility.TimeSpan();
                        _sendQty += e.BytesTransferred;
                        dataWriter.Write(receiveData.AsSpan(0, e.BytesTransferred));
                        dataWriter.Flush();
                    }
                    else
                    {
                        e.Dispose();

                        Close();
                        break;
                    }
                }
            }
            else
            {
                e.Dispose();
                Close();

            }
        }
        void Close()
        {
            base.Dispose();
            _IsOver = true;
            dataWriter.Write(Array.Empty<byte>());
            dataWriter.Flush();
            dataWriter.Dispose();
            this.targetStream.IsConnect = false;
            try
            {
                this.targetStream.Socket.Shutdown(SocketShutdown.Receive);
            }
            catch { }
            base.Dispose();
            // e.Dispose();
            if (receiveData.Length > 0)
            {
                System.Buffers.ArrayPool<byte>.Shared.Return(receiveData);
                receiveData = Array.Empty<byte>();
                if (this.ConfigKey != 0)
                {
                    Bridge.HttpBridge.Statistical(this.ConfigKey, _sendQty, _receiveQty);
                }

            }

        }
        public override void Receive(byte[] buffer, int offset, int size)
        {
            if (size == 0)
            {
                _IsOver = true;
                try
                {
                    this.targetStream.Socket.Shutdown(SocketShutdown.Receive);
                }
                catch { }
                base.Dispose();

            }
            else
            {
                _receiveQty += size;
            }
            base.Receive(buffer, offset, size);
        }
        protected override Task WriteAsync(byte[] buffer, int offset, int count)
        {
            return targetStream?.Socket?.SendAsync(new ArraySegment<byte>(buffer, offset, count));
        }

        void INetBridgePrepare.Prepare(byte[] bytes, int offset, int size)
        {
            switch (bytes[offset])
            {
                case 0x00:
                    Task.Run(async () =>
                    {

                        try
                        {
                            if (_size > 0)
                            {
                                // this.dataWriter.Write(receiveData.AsSpan(0, _size));

                                using (var view = NetCache.Share.CreateAccessor(_sharePosition, _size))
                                {
                                    int size = 0;

                                    while ((size = await view.ReadAsync(receiveData, 0, receiveData.Length)) > 0)
                                    {
                                        this.dataWriter.Write(new ArraySegment<byte>(receiveData, 0, size));
                                    }
                                }
                                this.dataWriter.Flush();
                            }
                            else
                            {
                                await targetStream.Socket.SendAsync("HTTP/1.1 200 Connection Established\r\n\r\n".UTF8());//.WriteBytes(buffer, 0)));

                            }
                            SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                            if (receiveData.Length == 0)
                                receiveData = System.Buffers.ArrayPool<byte>.Shared.Rent(512);
                            eventArgs.SetBuffer(receiveData);
                            eventArgs.Completed += Http;
                            if (targetStream.IsConnect && !this.targetStream.Socket.ReceiveAsync(eventArgs))
                            {
                                ProcessReceive(eventArgs);
                            }

                        }
                        catch
                        {
                            targetStream.IsConnect = false;
                            targetStream.Socket.Close();
                            if (receiveData.Length > 0)
                            {
                                System.Buffers.ArrayPool<byte>.Shared.Return(receiveData);
                                receiveData = Array.Empty<byte>();
                            }
                        }
                    });
                    break;
                case 0x01:
                    _IsOver = true;
                    Task.Run(async () =>
                        {

                            try
                            {
                                if (_size == 0)
                                {

                                    await targetStream.Socket.SendAsync("HTTP/1.1 403 Forbidden\r\n\r\n".UTF8());//.WriteBytes(buffer, 0)));

                                }
                                targetStream.Socket.Shutdown(SocketShutdown.Both);

                            }
                            catch
                            {

                            }
                            finally
                            {
                                targetStream.Socket.Close();

                                if (receiveData.Length > 0)
                                {
                                    System.Buffers.ArrayPool<byte>.Shared.Return(receiveData);
                                    receiveData = Array.Empty<byte>();
                                }


                            }
                        });
                    break;
            }
        }
        public override void Dispose()
        {
            base.Dispose();
        }
        public class WebProxy : Mime
        {
            public WebProxy() : base(new ByteChunk())
            {
            }

            public StringValue UserAgent = StringValue.Empty;

            protected override bool Header(StringValue key, MimeHeadKey headKey, StringValue value)
            {
                if (headKey == MimeHeadKey.UserAgent)
                {
                    UserAgent = value;
                }
                return false;
            }
        }

        static readonly StringValue EXIT = new StringValue("exit");
        static byte[] DNSAddr(StringValue domainName, StringValue clientId)
        {

            var domains = DnsServer.ParentDomain(domainName);
            if (domainName.Span.EndsWith(Socks5Server.ProxyDomain.Span))
            {
                var indexs = new Dictionary<uint, bool>();
                var ms = HotCache.Find(new ProxySite());
                indexs.Add(0, false);
                foreach (var m in ms)
                {
                    var value3 = m.ProxyIP.UInt32() ?? 0;
                    if (value3 != 0)
                    {
                        if (indexs.TryGetValue(value3, out var value33))
                        {
                            if (m.Type.Int32() == 1)
                            {

                                if (value33 == false)
                                {
                                    indexs[value3] = true;
                                }
                            }
                        }
                        else
                        {
                            indexs[value3] = m.Type.Int32() == 1;
                        }
                    }
                }

                var proxys = indexs.Keys.ToArray();
                Array.Sort(proxys);

                var value = domainName.Slice(0, domainName.Length - Socks5Server.ProxyDomain.Length - 1);
                if (value.IsEmpty == false)
                {

                    int v = value.Span.IndexOf((byte)'-');
                    if (v == -1)
                    {
                        v = value.Span.IndexOf((byte)'.');
                    }
                    if (v > -1 && Utility.TryParse(value.Slice(v + 1).Span, 10, out var proxyId))
                    {
                        if (proxyId < proxys.Length)
                        {
                            if (indexs.TryGetValue(proxys[proxyId], out var value33))
                            {
                                if (value33)
                                {
                                    var bufer = new byte[7] { 0x07, 0x04, 0, 0, 0, 0, 0 };
                                    proxys[proxyId].StringValue().Span.CopyTo(bufer.AsSpan(2));
                                    return bufer;// proxys[proxyId].StringValue().Span.ToArray();// };//[ySite.ProxyType.Span) };

                                }
                            }
                        }
                    }
                }
                return new byte[2] { 0x07, 0x00 };
            }
            var proxySite = HotCache.Find(new ProxySite { Domain = domainName }, "Domain", domains).OrderByDescending(d => d.Domain.Length).FirstOrDefault();
            if (proxySite != null)
            {
                var ProxyType = proxySite.ProxyIP.UInt32() ?? 0;

                if (ProxyType != 0 && proxySite.Type.Int32() == 1)
                {
                    int value = 0;
                    if (proxySite.ProxyIP.Length > 4)
                    {
                        Utility.MD5(domainName.Span);//, requestData.AsSpan(400));

                        var md5 = Utility.IntParse(Utility.MD5(domainName.Span)).StringValue();
                        var query = proxySite.RecursiveQuery ?? StringValue.Empty;

                        int iplen = proxySite.ProxyIP.Length;
                        if (iplen < query.Length)
                        {
                            query = query.Slice(0, iplen);
                        }
                        value = query.Span.IndexOf(md5.Span);
                        if (value == -1)
                        {
                            if (query.Length != iplen)
                            {
                                if (query.Length < iplen)
                                {
                                    var t = new byte[query.Length + 4];
                                    query.Span.CopyTo(t);
                                    query = new StringValue(t);
                                }
                                else
                                {
                                    query = query.Slice(0, iplen);
                                }
                                md5.Span.CopyTo(query.Span.Slice(query.Length - 4));
                            }
                            else
                            {
                                query.Span.Slice(4, query.Length - 4).CopyTo(query.Span);
                                md5.Span.CopyTo(query.Span.Slice(query.Length - 4));
                            }

                            HotCache.Put(new ProxySite
                            {
                                Domain = proxySite.Domain,
                                RecursiveQuery = query,//new StringValue(t)
                            });
                            value = ((query.Length - 4) / 4) % (proxySite.ProxyIP.Length / 4);
                        }
                        else
                        {
                            value = (value / 4) % (proxySite.ProxyIP.Length / 4);
                        }
                    }

                    var bufer = new byte[7] { 0x07, 0x04, 0, 0, 0, 0, 0 };

                    proxySite.ProxyIP.Slice(value * 4, 4).Span.CopyTo(bufer.AsSpan(2));
                    return bufer;
                }
                else
                {

                    return new byte[2] { 0x07, 0x00 };
                }
            }

            return new byte[2] { 0x00, 0x00 };
        }
        public static byte[] HttpsProxyAsync(StringValue clientIP, StringValue domain, ushort port)
        {
            var p = WebServlet.GetSiteInfo(domain);
            var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(100);
            try
            {
                var value = domain.Span;
                if (value[0] == 'B')
                {
                    return DNSAddr(domain.Slice(1), clientIP);
                }
                else if (value[0] == 'A')
                {
                    var domainName = domain.Slice(1);
                    if (domainName.Span.EndsWith(Socks5Server.ProxyDomain.Span))
                    {
                        buffer[0] = 0x07;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                    var domains = DnsServer.ParentDomain(domainName);
                    var proxySite = HotCache.Find(new ProxySite { Domain = domainName }, "Domain", domains).OrderByDescending(d => d.Domain.Length).FirstOrDefault();
                    if (proxySite != null)
                    {
                        buffer[0] = 0x07;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                    else
                    {
                        buffer[0] = 0x00;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                }
                else if (value[0] < 'A')
                {
                    var userName = domain.Slice(1, value[0]);

                    var userPwd = domain.Slice(1 + value[0] + 1, value[1 + value[0]]);
                    var uLen = userName.Length + 1 + userPwd.Length + 1;

                    userName = userName.Split((byte)'@').First();// domain.Slice(1, value[0]);
                    switch (value[uLen])
                    {
                        case 0x03:
                            {
                                domain = domain.Slice(uLen + 2);
                                var ip = NetProxy.DNSToIPAsync(domain.UTF8()).Result.FirstOrDefault();
                                var (check, ipAddress, appPort, errorMsg) = Socks5Server.Check(userName, ip, port, clientIP, userPwd);
                                if (check != 0x00)
                                {
                                    buffer[0] = 0x00;
                                    buffer[1] = 0x00;
                                    return buffer.AsSpan(0, 2).ToArray();
                                }
                                else
                                {

                                    buffer[0] = 0x05;
                                    buffer[1] = (byte)(appPort >> 8);
                                    buffer[2] = (byte)(appPort & 0xff);
                                    ipAddress.TryWriteBytes(buffer.AsSpan(3), out var qty);
                                    // return
                                    return buffer.AsSpan(0, qty + 3).ToArray();
                                }
                            }
                        case 0x01:
                            {
                                var ip2 = new IPAddress(value.Slice(uLen + 1, 4));
                                var (check, ipAddress, appPort, errorMsg) = Socks5Server.Check(userName, ip2, port, clientIP, userPwd);
                                if (check != 0x00)
                                {
                                    buffer[0] = 0x00;
                                    buffer[1] = 0x00;
                                    return buffer.AsSpan(0, 2).ToArray();
                                }
                                else
                                {

                                    buffer[0] = 0x05;
                                    buffer[1] = (byte)(appPort >> 8);
                                    buffer[2] = (byte)(appPort & 0xff);
                                    ipAddress.TryWriteBytes(buffer.AsSpan(3), out var qty);
                                    // return
                                    return buffer.AsSpan(0, qty + 3).ToArray();
                                }
                            }
                        case 0x04:
                            {
                                var ip2 = new IPAddress(value.Slice(uLen + 1, 16));

                                var (check, ipAddress, appPort, errorMsg) = Socks5Server.Check(userName, ip2, port, clientIP, userPwd);
                                if (check != 0x00)
                                {
                                    buffer[0] = 0x00;
                                    buffer[1] = 0x00;
                                    return buffer.AsSpan(0, 2).ToArray();
                                }
                                else
                                {

                                    buffer[0] = 0x05;
                                    buffer[1] = (byte)(appPort >> 8);
                                    buffer[2] = (byte)(appPort & 0xff);
                                    ipAddress.TryWriteBytes(buffer.AsSpan(3), out var qty);
                                    // return
                                    return buffer.AsSpan(0, qty + 3).ToArray();
                                }
                            }
                        default:
                            buffer[0] = 0x00;
                            buffer[1] = 0x00;
                            return buffer.AsSpan(0, 2).ToArray();
                    }

                }
                if (p.IsHome || p.Site != null || p.SiteHost != null)
                {
                    buffer[0] = 0x06;
                    buffer[1] = 0x00;
                    return buffer.AsSpan(0, 2).ToArray();
                }
                if (domain.Span.EndsWith(WebServlet.MainDomainValue.Span))
                {
                    var t = HttpBridge.Bridge(domain).Result;
                    if (t != null)
                    {
                        buffer[0] = 0x08;
                        buffer[1] = 0x04;
                        System.Buffers.Binary.BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(2), t.Key.Value);
                        buffer[6] = 0x00;
                        return buffer.AsSpan(0, 7).ToArray();

                    }
                    else
                    {

                        buffer[0] = 0x06;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                }

                // ushort port = 443;
                buffer[1] = (byte)(port >> 8);
                buffer[2] = (byte)(port & 0xFF);
                if (domain.Span.EndsWith(Socks5Server.ProxyDomain.Span))
                {
                    if (domain.Length - Socks5Server.ProxyDomain.Length < 2)
                    {
                        buffer[0] = 0x00;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                    else if (domain.Span.StartsWith(EXIT.Span))
                    {
                        var ts = UMC.Bridge.SocksUser.Cache.Find(new UMC.Bridge.SocksUser
                        {
                            UserAgent = clientIP,
                            Port = port.StringValue()
                        }, 0, out var _);
                        foreach (var t in ts)
                        {
                            UMC.Bridge.SocksUser.Cache.Delete(t);
                        }

                        buffer[0] = 0x00;
                        buffer[1] = 0x00;
                        return buffer.AsSpan(0, 2).ToArray();
                    }
                    else
                    {

                        var domainHeader = domain.Slice(0, domain.Length - Socks5Server.ProxyDomain.Length);

                        int domainEnd = domainHeader.Span.LastIndexOf((byte)'.');

                        var tva = domain.Slice(0, domainEnd);

                        var buffer2 = UMC.Security.Base32Encoding.ToBytes(domain.Slice(0, domainEnd - 2).UTF8().ToUpper());


                        switch (tva.Span[tva.Length - 2])
                        {
                            case (byte)'-':
                                var key = BitConverter.ToInt32(buffer2.AsSpan(buffer2.Length - 4));
                                var username = new StringValue(buffer2, 0, buffer2.Length - 4);
                                UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                {
                                    ClientIP = Utility.IntParse(Utility.MD5(username.Span)).StringValue(),// username ,
                                    Port = port.StringValue(),
                                    UserAgent = clientIP,// md5.StringValue(),
                                    Username = new StringValue($"{username}@{UMC.Data.Utility.Parse36Encode(key)}"),
                                    ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                    ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan()))
                                });
                                buffer[0] = 0x03;
                                buffer[3] = (byte)APIProxy.Uri.Host.WriteBytes(buffer, 4);
                                var index = buffer[3] + 4;
                                var len = clientIP.Length + 6;
                                buffer[index] = (byte)len;
                                index++;
                                buffer[index] = 0x03;
                                buffer[index + 1] = (byte)(len - 2);

                                BitConverter.TryWriteBytes(buffer.AsSpan(index + 2), Utility.IntParse(WebServlet.AppId.Span));
                                clientIP.Span.CopyTo(buffer.AsSpan(index + 6));
                                index += len;
                                buffer[index] = 0x00;

                                return buffer.AsSpan(0, index + 1).ToArray();
                            case (byte)'.':

                                buffer2.AsSpan(4).CopyTo(buffer);
                                var size = buffer2.Length - 4;
                                WebServlet.AppSecret.Span.CopyTo(buffer.AsSpan(buffer2.Length - 4));
                                size += WebServlet.AppSecret.Length;
                                UMC.Data.Utility.MD5(buffer.AsSpan(0, size), buffer.AsSpan(size, 16));
                                var time = BitConverter.ToUInt32(buffer) + 0L;
                                var now2 = UMC.Data.Utility.TimeSpan() + 0L;
                                if (UMC.Data.Utility.IntParse(buffer.AsSpan(size, 16)) == BitConverter.ToInt32(buffer2))
                                {
                                    if (Math.Abs(time - now2) <= 300)
                                    {
                                        UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                        {
                                            ClientIP = new StringValue(buffer, 4, 4),
                                            Port = port.StringValue(),
                                            UserAgent = clientIP,
                                            ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                            ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan(DateTime.Now.AddHours(1))))
                                        });
                                    }
                                }
                                break;


                        }

                        buffer[0] = 0x00; ;
                        buffer[1] = 0x00; ;
                        return buffer.AsSpan(0, 2).ToArray();

                    }
                }
                else
                {
                    int configKey = Utility.IntParse(WebServlet.AppId.Span);

                    if (Utility.IsInternalIP(clientIP.Span) == false)
                    {
                        var sockUser = UMC.Bridge.SocksUser.Cache.Find(new UMC.Bridge.SocksUser
                        {
                            UserAgent = clientIP,
                            Port = port.StringValue()
                        }, 0, out var _).FirstOrDefault();
                        var extTime = sockUser?.ExpirationTime.UInt32() ?? 0;
                        var now = UMC.ITME.Utility.TimeSpan();
                        if (extTime < now)
                        {
                            buffer[0] = 0x02;
                            buffer[1] = 0x00;
                            return buffer.AsSpan(0, 2).ToArray();
                        }
                        else
                        {
                            var valueTime = extTime - sockUser.ActiveTime.UInt32().Value;
                            BitConverter.TryWriteBytes(sockUser.ExpirationTime.Span, now + valueTime);
                            BitConverter.TryWriteBytes(sockUser.ActiveTime.Span, now);

                        }

                        var puserIndex = sockUser.Username.Span.IndexOf("@"u8);
                        if (puserIndex > -1)
                        {
                            configKey = UMC.Data.Utility.Parse36Decode(sockUser.Username.Slice(puserIndex + 1).UTF8());
                        }
                    }
                    var proxySite = HotCache.Find(new ProxySite { Domain = domain }, "Domain", DnsServer.ParentDomain(domain)).FirstOrDefault();

                    System.Buffers.Binary.BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(3), configKey);

                    int prType = proxySite?.Type.Int32() == 1 ? 0 : (proxySite?.ProxyIP.Int32() ?? 0);
                    if (prType == 0)
                    {
                        buffer[0] = 0x01;
                        buffer[7] = (byte)domain.Length;//.UTF8()
                        domain.Span.CopyTo(buffer.AsSpan(8));
                        var size = domain.Length + 8;
                        buffer[size] = 0x00;
                        return buffer.AsSpan(0, size + 1).ToArray();
                    }
                    else
                    {
                        buffer[0] = 0x04;
                        buffer[7] = 4;
                        BitConverter.TryWriteBytes(buffer.AsSpan(8), prType);
                        var size = 4 + 8;
                        buffer[size] = 0x00;
                        return buffer.AsSpan(0, size + 1).ToArray();
                    }

                }
            }
            finally
            {
                System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
            }
        }
        public static async Task HttpsProxyAsync(Socket socket, TlsSite tlsSite, int configKey, Memory<byte> header)
        {
            var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(100);
            var timeOut = new CancellationTokenSource(10000);

            Socket proxySocket = null;
            bool isProxy = false;
            try
            {
                proxySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                var domain = tlsSite.Host;

                ushort port = 443;
                var address = (socket.RemoteEndPoint as IPEndPoint).Address;
                if (address.IsIPv4MappedToIPv6)
                {
                    address = address.MapToIPv4();
                }

                address.TryWriteBytes(buffer, out var bLeng);
                var clientIP = new StringValue(buffer.AsSpan(0, bLeng).ToArray());

                if (domain.Span.EndsWith(Socks5Server.ProxyDomain.Span))
                {

                    if (domain.Length - Socks5Server.ProxyDomain.Length < 2)
                    {

                        await proxySocket.ConnectAsync(APIProxy.Uri.Host, port, timeOut.Token);

                        var len = clientIP.Length + 8;

                        buffer[0] = 0x03;
                        buffer[1] = (byte)(len - 2);
                        BitConverter.TryWriteBytes(buffer.AsSpan(2), port);
                        BitConverter.TryWriteBytes(buffer.AsSpan(4), 443);
                        clientIP.Span.CopyTo(buffer.AsSpan(8));

                        await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, len), timeOut.Token);
                        await proxySocket.SendAsync(header, timeOut.Token);

                    }
                    else if (domain.Span.StartsWith(EXIT.Span))
                    {
                        var ts = UMC.Bridge.SocksUser.Cache.Find(new UMC.Bridge.SocksUser
                        {
                            UserAgent = clientIP,
                            Port = port.StringValue()
                        }, 0, out var _);
                        foreach (var t in ts)
                        {
                            UMC.Bridge.SocksUser.Cache.Delete(t);
                        }
                        return;
                    }
                    else
                    {

                        var domainHeader = domain.Slice(0, domain.Length - Socks5Server.ProxyDomain.Length);

                        int domainEnd = domainHeader.Span.LastIndexOf((byte)'.');

                        var tva = domain.Slice(0, domainEnd);

                        var buffer2 = UMC.Security.Base32Encoding.ToBytes(domain.Slice(0, domainEnd - 2).UTF8().ToUpper());


                        switch (tva.Span[tva.Length - 2])
                        {
                            case (byte)'-':
                                var key = BitConverter.ToInt32(buffer2.AsSpan(buffer2.Length - 4));
                                var username = new StringValue(buffer2, 0, buffer2.Length - 4);
                                UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                {
                                    ClientIP = Utility.IntParse(Utility.MD5(username.Span)).StringValue(),// username ,
                                    Port = port.StringValue(),
                                    UserAgent = clientIP,// md5.StringValue(),
                                    Username = new StringValue($"{username}@{UMC.Data.Utility.Parse36Encode(key)}"),
                                    ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                    ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan()))
                                });

                                var len = clientIP.Length + 6;
                                buffer[0] = 0x03;
                                buffer[1] = (byte)(len - 2);
                                BitConverter.TryWriteBytes(buffer.AsSpan(2), Utility.IntParse(WebServlet.AppId.Span));
                                clientIP.Span.CopyTo(buffer.AsSpan(6));

                                await proxySocket.ConnectAsync(APIProxy.Uri.Host, port, timeOut.Token);
                                await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, len), timeOut.Token);
                                await proxySocket.SendAsync(header, timeOut.Token);

                                break;
                            case (byte)'.':
                                buffer2.AsSpan(4).CopyTo(buffer);
                                var size = buffer2.Length - 4;
                                WebServlet.AppSecret.Span.CopyTo(buffer.AsSpan(buffer2.Length - 4));
                                size += WebServlet.AppSecret.Length;
                                UMC.Data.Utility.MD5(buffer.AsSpan(0, size), buffer.AsSpan(size, 16));
                                var time = BitConverter.ToUInt32(buffer) + 0L;
                                var now2 = UMC.Data.Utility.TimeSpan() + 0L;
                                if (UMC.Data.Utility.IntParse(buffer.AsSpan(size, 16)) == BitConverter.ToInt32(buffer2))
                                {
                                    if (Math.Abs(time - now2) <= 300)
                                    {
                                        UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                        {
                                            ClientIP = new StringValue(buffer, 4, 4),
                                            Port = port.StringValue(),
                                            UserAgent = clientIP,
                                            ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                            ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan(DateTime.Now.AddHours(1))))
                                        });
                                    }
                                }
                                // await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 403 Forbidden\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);

                                return;
                        }

                        // var domainHeader = domain.Slice(0, domain.Length - Socks5Server.ProxyDomain.Length);
                        // int domainEnd = domainHeader.Span.LastIndexOf((byte)'.');

                        // var buffer2 = UMC.Security.Base32Encoding.ToBytes(domain.Slice(0, domainEnd).UTF8().ToUpper());
                        // var bsize = buffer2.Length;
                        // buffer2.AsSpan().CopyTo(buffer);

                        // BitConverter.TryWriteBytes(buffer.AsSpan(bsize), port);
                        // BitConverter.TryWriteBytes(buffer.AsSpan(2 + bsize), 443);
                        // clientIP.Span.CopyTo(buffer.AsSpan(6 + bsize));
                        // bsize += 6 + clientIP.Length;

                        // UMC.Data.Utility.MD5(buffer.AsSpan(4, bsize - 4), buffer.AsSpan(bsize, 16));
                        // if (UMC.Data.Utility.IntParse(buffer.AsSpan(bsize, 16)) == BitConverter.ToInt32(buffer2))
                        // {
                        //     var time = BitConverter.ToUInt32(buffer2.AsSpan(4)) + 0L;
                        //     var now2 = UMC.Data.Utility.TimeSpan() + 0L;
                        //     if (Math.Abs(time - now2) <= 300)
                        //     {
                        //         var key = BitConverter.ToInt32(buffer2.AsSpan(8));
                        //         var username = new StringValue(buffer2, 12, buffer2.Length - 12);
                        //         UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                        //         {
                        //             ClientIP = username,
                        //             Port = port.StringValue(),
                        //             UserAgent = clientIP,
                        //             Username = new StringValue($"{username}@{UMC.Data.Utility.Parse36Encode(key)}"),
                        //             ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                        //             ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan(DateTime.Now.AddHours(1))))
                        //         });

                        //     }

                        // }
                    }

                }
                else
                {

                    var proxySite = HotCache.Find(new ProxySite { Domain = tlsSite.Host }, "Domain", DnsServer.ParentDomain(tlsSite.Host)).FirstOrDefault();

                    if (configKey == 0 && Utility.IsInternalIP(clientIP.Span) == false && tlsSite.IsSecure == false)
                    {
                        var sockUser = UMC.Bridge.SocksUser.Cache.Find(new UMC.Bridge.SocksUser
                        {
                            UserAgent = clientIP,
                            Port = port.StringValue()
                        }, 0, out var _).FirstOrDefault();
                        var extTime = sockUser?.ExpirationTime.UInt32() ?? 0;
                        var now = UMC.ITME.Utility.TimeSpan();
                        if (extTime < now)
                        {
                            return;
                        }
                        else
                        {
                            var value = extTime - sockUser.ActiveTime.UInt32().Value;
                            BitConverter.TryWriteBytes(sockUser.ExpirationTime.Span, now + value);
                            BitConverter.TryWriteBytes(sockUser.ActiveTime.Span, now);

                        }

                        var puserIndex = sockUser.Username.Span.IndexOf("@"u8);
                        if (puserIndex > -1)
                        {
                            configKey = UMC.Data.Utility.Parse36Decode(sockUser.Username.Slice(puserIndex + 1).UTF8());
                        }
                    }
                    int prType = proxySite?.Type.Int32() == 1 ? 0 : (proxySite?.ProxyIP.Int32() ?? 0);
                    System.Net.IPAddress ipAddress;
                    if (prType == 0)
                    {
                        var ipAddresses = await NetProxy.DNSToIPAsync(domain.UTF8(), timeOut.Token);

                        if (ipAddresses.Length == 0)
                        {
                            return;
                        }
                        ipAddress = ipAddresses[0];
                        if (Utility.IsInternalIP(ipAddress))
                        {
                            return;
                        }
                        await proxySocket.ConnectAsync(ipAddress, port, timeOut.Token);
                    }
                    else
                    {
                        ipAddress = new System.Net.IPAddress(prType.StringValue().Span);

                        await proxySocket.ConnectAsync(ipAddress, port, timeOut.Token);
                        buffer[0] = 0x04;
                        buffer[1] = 0x04;
                        System.Buffers.Binary.BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(2), configKey);
                        buffer[6] = (byte)(header.Length >> 8);
                        buffer[7] = (byte)(header.Length & 0xff);

                        await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, 8));
                        Socks5Server.OR(header.Span, 0x04);
                    }

                    await proxySocket.SendAsync(header, timeOut.Token);

                }
                isProxy = true;

                var clientRelay = new RelayAsyncArgs.Relay(socket);
                var proxyRelay = new RelayAsyncArgs.Relay(proxySocket);
                if (configKey != 0)// > -1)
                {
                    new RelayAsyncArgs(clientRelay, proxyRelay) { ConfigKey = configKey, IsSend = true };
                    new RelayAsyncArgs(proxyRelay, clientRelay) { ConfigKey = configKey, IsSend = false }; ;
                }
                else
                {
                    new RelayAsyncArgs(clientRelay, proxyRelay);
                    new RelayAsyncArgs(proxyRelay, clientRelay);
                }
            }
            catch//(Exception ex)
            {

                GC.Collect();
                isProxy = false;
            }
            finally
            {
                if (isProxy == false)
                {
                    socket.Close();
                    socket.Dispose();
                    proxySocket?.Close();
                    proxySocket?.Dispose();
                }
                System.Buffers.ArrayPool<byte>.Shared.Return(buffer);

            }
        }
        public static async void HttpsProxyAsync(Socket socket, int repostIP, Memory<byte> header)
        {

            var timeOut = new CancellationTokenSource(60000);

            Socket proxySocket = null;// new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            bool isProxy = false;
            try
            {
                proxySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                using (var webProxy = new WebProxy())
                {
                    var buffer = webProxy.Memory.Chunk;

                    int psize = 0;
                    if (header.Length > 0)
                    {
                        header.CopyTo(buffer);
                        psize = header.Length;
                    }
                    else
                    {
                        psize = await socket.ReceiveAsync(new ArraySegment<byte>(buffer, 0, buffer.Length), timeOut.Token);
                    }
                    if (psize < 5)
                    {
                        return;
                    }
                    while (buffer.AsSpan(psize - 4, 4).SequenceEqual(Mime.HeaderEnd) == false)
                    {
                        int len = await socket.ReceiveAsync(new ArraySegment<byte>(buffer, psize, buffer.Length - psize), timeOut.Token);
                        if (len == 0)
                        {
                            return;
                        }
                        psize += len;
                    }
                    var b = buffer[8];
                    buffer[8] = (byte)'/';
                    webProxy.Receive(buffer, 0, psize);

                    if (webProxy.Frist != HttpMethod.CONNECT)
                    {
                        return;
                    }

                    webProxy.Second.Span[0] = b;

                    var sp = webProxy.Second.Split(":"u8);
                    var domain = new StringValue(sp[0].Span.ToArray());

                    var port = (ushort)(UMC.Data.Utility.TryParse(sp[1].Span, 10, out int p) ? p : 80);

                    var pLocalPort = (ushort)(socket.LocalEndPoint as IPEndPoint).Port;
                    var md5 = webProxy.UserAgent.Length > 0 ? UMC.Data.Utility.IntParse(UMC.Data.Utility.MD5(webProxy.UserAgent.Span)) : 0;
                    var address = (socket.RemoteEndPoint as IPEndPoint).Address;
                    address.TryWriteBytes(buffer, out var bLeng);

                    var clientIP = new StringValue(buffer.AsSpan(0, bLeng).ToArray());

                    int configKey = 0;
                    if (domain.Span.EndsWith(Socks5Server.ProxyDomain.Span))
                    {

                        if (domain.Length - Socks5Server.ProxyDomain.Length < 2)
                        {
                            await proxySocket.ConnectAsync(APIProxy.Uri.Host, port, timeOut.Token);
                            await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 200 Connection Established\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);

                            var len = clientIP.Length + 8;
                            int l = await socket.ReceiveAsync(new ArraySegment<byte>(buffer, len, buffer.Length - len), timeOut.Token);
                            buffer[0] = 0x03;
                            buffer[1] = (byte)(len - 2);
                            BitConverter.TryWriteBytes(buffer.AsSpan(2), pLocalPort);
                            BitConverter.TryWriteBytes(buffer.AsSpan(4), md5);
                            clientIP.Span.CopyTo(buffer.AsSpan(8));

                            await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, l + len), timeOut.Token);
                        }
                        else if (domain.Span.StartsWith(EXIT.Span))
                        {
                            UMC.Bridge.SocksUser.Cache.Delete(new UMC.Bridge.SocksUser
                            {
                                ClientIP = clientIP,
                                Port = pLocalPort.StringValue(),
                                UserAgent = md5.StringValue(),
                            });
                            await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 403 Forbidden\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                            return;
                        }
                        else
                        {
                            var domainHeader = domain.Slice(0, domain.Length - Socks5Server.ProxyDomain.Length);

                            int domainEnd = domainHeader.Span.LastIndexOf((byte)'.');

                            var tva = domain.Slice(0, domainEnd);

                            var buffer2 = UMC.Security.Base32Encoding.ToBytes(domain.Slice(0, domainEnd - 2).UTF8().ToUpper());

                            switch (tva.Span[tva.Length - 2])
                            {
                                case (byte)'-':
                                    var key = BitConverter.ToInt32(buffer2.AsSpan(buffer2.Length - 4));
                                    var username = new StringValue(buffer2, 0, buffer2.Length - 4);
                                    UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                    {
                                        ClientIP = clientIP,
                                        Port = pLocalPort.StringValue(),
                                        UserAgent = md5.StringValue(),
                                        Username = new StringValue($"{username}@{UMC.Data.Utility.Parse36Encode(key)}"),
                                        ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                        ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan()))
                                    });

                                    await proxySocket.ConnectAsync(APIProxy.Uri.Host, port, timeOut.Token);
                                    await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 200 Connection Established\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);

                                    var len = clientIP.Length + 6;
                                    int l = await socket.ReceiveAsync(new ArraySegment<byte>(buffer, len, buffer.Length - len), timeOut.Token);
                                    buffer[0] = 0x03;
                                    buffer[1] = (byte)(len - 2);
                                    BitConverter.TryWriteBytes(buffer.AsSpan(2), Utility.IntParse(WebServlet.AppId.Span));
                                    clientIP.Span.CopyTo(buffer.AsSpan(6));

                                    await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, l + len), timeOut.Token);

                                    break;
                                case (byte)'.':
                                    buffer2.AsSpan(4).CopyTo(buffer);
                                    var size = buffer2.Length - 4;
                                    WebServlet.AppSecret.Span.CopyTo(buffer.AsSpan(buffer2.Length - 4));
                                    size += WebServlet.AppSecret.Length;
                                    UMC.Data.Utility.MD5(buffer.AsSpan(0, size), buffer.AsSpan(size, 16));
                                    var time = BitConverter.ToUInt32(buffer) + 0L;
                                    var now2 = UMC.Data.Utility.TimeSpan() + 0L;
                                    if (UMC.Data.Utility.IntParse(buffer.AsSpan(size, 16)) == BitConverter.ToInt32(buffer2))
                                    {
                                        if (Math.Abs(time - now2) <= 300)
                                        {
                                            UMC.Bridge.SocksUser.Cache.Put(new UMC.Bridge.SocksUser
                                            {
                                                ClientIP = clientIP,
                                                Port = pLocalPort.StringValue(),
                                                UserAgent = md5.StringValue(),
                                                ActiveTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan())),
                                                ExpirationTime = new StringValue(BitConverter.GetBytes(UMC.Data.Utility.TimeSpan(DateTime.Now.AddHours(1))))
                                            });
                                        }
                                    }
                                    await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 403 Forbidden\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);

                                    return;
                            }
                        }

                    }
                    else
                    {
                        var sPort = pLocalPort.StringValue();
                        var sockUser = SocksUser.Cache.Get(new SocksUser
                        {
                            ClientIP = clientIP,
                            UserAgent = md5.StringValue(),
                            Port = sPort
                        });
                        var extTime = sockUser?.ExpirationTime.UInt32() ?? 0;
                        var now = UMC.ITME.Utility.TimeSpan();
                        if (extTime < now)
                        {
                            await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 403 Forbidden\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                            return;
                        }
                        else
                        {
                            var value = extTime - sockUser.ActiveTime.UInt32().Value;
                            BitConverter.TryWriteBytes(sockUser.ExpirationTime.Span, now + value);
                            BitConverter.TryWriteBytes(sockUser.ActiveTime.Span, now);

                        }
                        var puserIndex = sockUser.Username.Span.IndexOf("@"u8);
                        if (puserIndex > -1)
                        {
                            configKey = UMC.Data.Utility.Parse36Decode(sockUser.Username.Slice(puserIndex + 1).UTF8());
                        }
                        var proxySite = HotCache.Find(new ProxySite { Domain = domain }, "Domain", DnsServer.ParentDomain(domain)).FirstOrDefault();

                        System.Net.IPAddress ipAddress;

                        if (proxySite != null)
                        {

                            int prType = proxySite?.Type.Int32() == 1 ? 0 : (proxySite?.ProxyIP.Int32() ?? 0);

                            if (prType == 0)
                            {
                                prType = repostIP;
                            }
                            if (prType != 0)
                            {
                                ipAddress = new System.Net.IPAddress(prType.StringValue().Span);
                                await proxySocket.ConnectAsync(ipAddress, port, timeOut.Token);
                                await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 200 Connection Established\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);

                                await socket.ReceiveAsync(new ArraySegment<byte>(buffer, 0, 5));

                                int length = ((buffer[3] << 8) | buffer[4]) + HttpsStream.TlsFrameHelper.HeaderSize;
                                var buffer2 = System.Buffers.ArrayPool<byte>.Shared.Rent(length);
                                try
                                {

                                    Array.Copy(buffer, 0, buffer2, 0, 5);
                                    var size = 5;
                                    while (size < length)
                                    {
                                        int len = await socket.ReceiveAsync(new ArraySegment<byte>(buffer2, size, buffer2.Length - size), timeOut.Token);
                                        if (len == 0)
                                        {
                                            return;
                                        }
                                        else
                                        {
                                            size += len;
                                        }
                                    }
                                    buffer[0] = 0x04;
                                    buffer[1] = 0x04;
                                    System.Buffers.Binary.BinaryPrimitives.WriteInt32BigEndian(buffer.AsSpan(2), configKey);
                                    buffer[6] = (byte)(length >> 8);
                                    buffer[7] = (byte)(length & 0xff);

                                    await proxySocket.SendAsync(new ArraySegment<byte>(buffer, 0, 8));

                                    Socks5Server.OR(buffer2.AsSpan(0, length), 0x04);
                                    await proxySocket.SendAsync(new ArraySegment<byte>(buffer2, 0, size));
                                }
                                finally
                                {
                                    System.Buffers.ArrayPool<byte>.Shared.Return(buffer2);
                                }
                            }
                            else
                            {
                                var ipAddresses = await NetProxy.DNSToIPAsync(domain.UTF8(), timeOut.Token);

                                if (ipAddresses.Length == 0)
                                {
                                    await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 502 Bad Gateway\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                                    return;
                                }
                                ipAddress = ipAddresses[0];
                                if (UMC.ITME.Utility.IsInternalIP(ipAddress))
                                {
                                    await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 502 Bad Gateway\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                                    return;
                                }
                                await proxySocket.ConnectAsync(ipAddress, port, timeOut.Token);

                                await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 200 Connection Established\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);


                            }
                        }
                        else
                        {
                            var ipAddresses = await NetProxy.DNSToIPAsync(domain.UTF8(), timeOut.Token);

                            if (ipAddresses.Length == 0)
                            {
                                await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 502 Bad Gateway\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                                return;
                            }
                            ipAddress = ipAddresses[0];
                            if (UMC.ITME.Utility.IsInternalIP(ipAddress))
                            {
                                await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 502 Bad Gateway\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);
                                return;
                            }
                            await proxySocket.ConnectAsync(ipAddress, port, timeOut.Token);

                            await socket.SendAsync(new ArraySegment<byte>(buffer, 0, "HTTP/1.1 200 Connection Established\r\n\r\n".WriteBytes(buffer, 0)), timeOut.Token);


                        }


                    }
                    isProxy = true;

                    var clientRelay = new RelayAsyncArgs.Relay(socket);
                    var proxyRelay = new RelayAsyncArgs.Relay(proxySocket);
                    if (configKey != 0)// > -1)
                    {
                        new RelayAsyncArgs(clientRelay, proxyRelay) { ConfigKey = configKey, IsSend = true };
                        new RelayAsyncArgs(proxyRelay, clientRelay) { ConfigKey = configKey, IsSend = false }; ;
                    }
                    else
                    {
                        new RelayAsyncArgs(clientRelay, proxyRelay);
                        new RelayAsyncArgs(proxyRelay, clientRelay);
                    }
                }

            }
            catch// (Exception ex)
            {
                isProxy = false;
            }
            finally
            {
                if (isProxy == false)
                {
                    socket.Close();
                    socket.Dispose();
                    proxySocket?.Close();
                    proxySocket?.Dispose();
                }
            }
        }


    }
}
